/*
 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

package org.box2dflash.common.math {

	/// A 2-by-2 matrix. Stored in column-major order.
	
	public class Mat22 {
		public function Mat22(angle:Number = 0, c1:Vec2 = null, c2:Vec2 = null) {
			if (c1 != null && c2 != null) {
				col1.v(c1);
				col2.v(c2);
			}
		else {
				var c:Number = Math.cos(angle);
				var s:Number = Math.sin(angle);
				col1.x = c; 
				col2.x = -s;
				col1.y = s; 
				col2.y = c;
			}
		}

//		public function set (angle:Number):void {
//			var c:Number = Math.cos(angle);
//			var s:Number = Math.sin(angle);
//			col1.x = c; 
//			col2.x = -s;
//			col1.y = s; 
//			col2.y = c;
//		}

		public function v(c1:Vec2, c2:Vec2):void {
			col1.v(c1);
			col2.v(c2);
		}

		public function copy():Mat22 {
			return new Mat22(0, col1, col2);
		}

		public function m(m:Mat22):void {
			col1.v(m.col1);
			col2.v(m.col2);
		}

		public function addM(m:Mat22):void {
			col1.x += m.col1.x;
			col1.y += m.col1.y;
			col2.x += m.col2.x;
			col2.y += m.col2.y;
		}

		public function identity():void {
			col1.x = 1.0; 
			col2.x = 0.0;
			col1.y = 0.0; 
			col2.y = 1.0;
		}

		public function zero():void {
			col1.x = 0.0; 
			col2.x = 0.0;
			col1.y = 0.0; 
			col2.y = 0.0;
		}

		public function get angle():Number {
			return Math.atan2(col1.y, col1.x);
		}

		public function invert(out:Mat22):Mat22 {
			var a:Number = col1.x; 
			var b:Number = col2.x; 
			var c:Number = col1.y; 
			var d:Number = col2.y;
			//var B:Mat22 = new Mat22();
			var det:Number = a * d - b * c;
			//Settings.Assert(det != 0.0);
			det = 1.0 / det;
			out.col1.x = det * d;	
			out.col2.x = -det * b;
			out.col1.y = -det * c;	
			out.col2.y = det * a;
			return out;
		}

		// Solve A * x = b
		public function solve(out:Vec2, bX:Number, bY:Number):Vec2 {
			//float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;
			var a11:Number = col1.x;
			var a12:Number = col2.x;
			var a21:Number = col1.y;
			var a22:Number = col2.y;
			//float32 det = a11 * a22 - a12 * a21;
			var det:Number = a11 * a22 - a12 * a21;
			//Settings.Assert(det != 0.0);
			det = 1.0 / det;
			out.x = det * (a22 * bX - a12 * bY);
			out.y = det * (a11 * bY - a21 * bX);
		
			return out;
		}

		public function abs():void {
			col1.abs();
			col2.abs();
		}

		public var col1:Vec2 = new Vec2();
		public var col2:Vec2 = new Vec2();
	}
}